// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: lucasyoo

#pragma once

#include <algorithm>

#include "coin2/exchange/base/feed/update.h"
#include "coin2/exchange/base/order/order.h"
#include "coin2/strategy/hamm/hamm_order_qty.h"
#include "coin2/strategy/hamm/util.h"

//------------------------------------
// HammPricer: Responsible for calculating optimal spread and reservation price
//------------------------------------
namespace coin2::strategy::hamm {

using coin2::exchange::base::feed::FeedUpdate;
using coin2::exchange::base::order::OrderUpdate;

class HammPricer {
 public:
  HammPricer(
      HammPricerConfig* config,
      double reserve,
      double lot_size,
      std::optional<double> lot_size_quote,
      double min_pos,
      double max_pos,
      int64_t strategy_created_time);

  void onBookFeed(const FeedUpdate& upd);
  void UpdateMidP(const FeedUpdate& upd);
  void UpdateTrade(const FeedUpdate& upd);
  void UpdatePos(double pos);
  void SetArbFreeBbo(std::pair<double, double> bbo, std::pair<bool, bool> is_adjust);
  void ResetArbFreeBbo();
  void UpdateFillInfo(double p, double q, int64_t ts, std::string side_str);

  void FullBookMidP(const FeedUpdate& upd);
  void FullBookWeightedMidP(const FeedUpdate& upd);
  double CalculateQ();

  // Guard Related
  void TotalGuardClipping();
  void MinMaxSpreadClipping();
  void ArbFreeBboClipping();
  void FillTimeLimitClipping();
  void FakePriceClipping();
  void FillDecayClipping();

  // Getter
  const std::pair<double, double>& OptimalBidAsk() const { return optimal_bid_ask_; }
  const std::pair<double, double>& Bbo() const { return bbo_; }
  const double& MidP() const { return midp_; }
  const double& Volatility() const { return volatility_; }
  OrderQtyGenerator* GetOrderQtyGenerator() const { return order_qty_generator_.get(); }
  TradeCollector* GetFillCollector() const { return fill_collector_.get(); }
  double GetClippedLotSize() const {
    return clipped_lot_size_.has_value() ? clipped_lot_size_.value() : lot_size_;
  }
  const HammPricerConfig& config() const { return config_; }

 private:
  std::unique_ptr<VolatilityCalc> vol_calc_{nullptr};
  std::unique_ptr<OrderQtyGenerator> order_qty_generator_{nullptr};
  std::unique_ptr<TradeCollector> trade_collector_{nullptr};
  std::unique_ptr<TradeCollector> fill_collector_{nullptr};
  std::unique_ptr<MovingAverage> midp_ma_collector_{nullptr};
  std::unique_ptr<MovingAverage> full_book_midp_collector_{nullptr};
  std::unique_ptr<MovingAverage> full_book_weighted_midp_collector_{nullptr};

  HammPricerConfig config_;
  int64_t strategy_created_time_;
  double init_base_qty_{0.0};
  double target_ratio_{50};
  std::pair<double, double> bbo_{0.0, 0.0};
  std::pair<double, double> arb_free_bbo_{0.0, 0.0};
  std::pair<bool, bool> is_adjust_{false, false};
  double midp_{0};
  double vwap_{0};
  double buy_vwap_{0};
  double sell_vwap_{0};
  double ma_{0};
  double vol_intensity_{-1};
  int64_t timestamp_{0};
  double gamma_{0};
  double kappa_{0};
  double volatility_;
  bool is_closing_time_infinite_{true};
  int64_t closing_timestamp_{1};
  double min_spread_bps_{0};
  double max_spread_bps_{0};
  double maker_fee_rate_{0};
  double base_qty_{0};
  double reservation_price_{0};
  double optimal_spread_{0};
  std::pair<double, double> optimal_bid_ask_{0, 0};
  std::string price_type_{"MIDP"};
  std::string spread_control_{"ACTIVE"};
  std::string min_max_control_{"midp"};
  double eta2_{0.0};
  int64_t fill_price_limit_;
  int64_t filled_buy_ts_{0};
  int64_t filled_sell_ts_{0};
  double filled_buy_price_{0};
  double filled_sell_price_{0};
  int trade_cnt_;
  int full_book_num_;
  double single_amount_;
  double total_amount_;
  double min_pos_;
  double max_pos_;
  double lot_size_;
  std::optional<double> lot_size_quote_{std::nullopt};
  std::optional<double> clipped_min_pos_{std::nullopt};
  std::optional<double> clipped_max_pos_{std::nullopt};
  std::optional<double> clipped_lot_size_{std::nullopt};
  std::string q_method_;
  double fake_out_fbw_bid_{0.0};
  double fake_out_fbw_ask_{0.0};
  double fake_out_fb_bid_{0.0};
  double fake_out_fb_ask_{0.0};
  std::string fake_method_;
  double fade_bps_{0.0};
  double fade_decay_sec_{0.0};
  double fade_bps_multiplier_;
  int64_t fill_num_hurdle_;
  std::vector<std::string> guard_methods_;
  double price_;
  double buy_filled_vwap_{0.0};
  double sell_filled_vwap_{0.0};
};
}  // namespace coin2::strategy::hamm
